package com.afdor.rws.event;

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 事件聚合根
 *
 * @author 悭梵
 * @date Created in 2018-08-14 9:56
 */
@ToString
@EqualsAndHashCode
public class AggregationEvent extends Event<List<Event>> implements Cloneable {

    /**
     * 冻结事件修改操作
     */
    private volatile boolean frozenModify = false;
    /**
     * 事件管理器中的事件队列
     */
    protected final LinkedBlockingQueue<Event> eventQueue = new LinkedBlockingQueue<>();

    AggregationEvent() {
        setType(Type.AGGREGATION_ROOT);
    }

    public boolean hasEvent(@NonNull Event event) {
        if (frozenModify) {
            throw new IllegalStateException("事件队列已冻结，不能执行该操作");
        }
        return this.eventQueue.contains(event);
    }


    public void addEvent(@NonNull Event event) throws IllegalAccessException {
        if (frozenModify) {
            throw new IllegalAccessException("事件队列已冻结，不能执行该操作");
        }
        Field parentIdField = FieldUtils.getDeclaredField(Event.class, "parentId", true);
        Object parentId = FieldUtils.readField(parentIdField, event, true);
        if (parentId == null || StringUtils.isBlank(parentId.toString())) {
            FieldUtils.writeField(parentIdField, event, this.getId(), true);
        } else if (!Objects.equals(parentId, this.getId())) {
            throw new IllegalAccessException("事件[" + event + "]中存在parentId已存在，无法执行聚合提交操作。请调整业务或分步提交。");
        }
        this.eventQueue.add(event);
    }

    public void removeEvent(@NonNull Event event) {
        if (frozenModify) {
            throw new IllegalStateException("事件队列已冻结，不能执行该操作");
        }
        this.eventQueue.remove(event);
    }

    public void clearEvent() {
        if (frozenModify) {
            throw new IllegalStateException("事件队列已冻结，不能执行该操作");
        }
        this.eventQueue.clear();
    }

    @Override
    public void setSource(List<Event> source) {
        if (frozenModify) {
            throw new IllegalStateException("事件队列已冻结，不能执行该操作");
        }
        super.setSource(source);
    }

    /**
     * 冻结事件队列操作
     *
     * @param newFrozenEventList 生成冻结事件队列
     */
    public void frozenModify(boolean newFrozenEventList) {
        if (!frozenModify) {
            synchronized (this) {
                if (!frozenModify) {
                    if (newFrozenEventList) {
                        setSource(Collections.unmodifiableList(new ArrayList<Event>(eventQueue)));
                    }
                    clearEvent();
                    frozenModify = true;
                }
            }
        }
    }

    @ToString
    public static class EventBuilder {
        /**
         * 事件源
         */
        @NonNull
        private List<Event> source;

        public EventBuilder source(@NonNull List<Event> source) {
            this.source = source;
            return this;
        }

        /**
         * 生成Type.AGGREGATION_ROOT事件对象
         *
         * @return
         */
        public AggregationEvent build() {
            AggregationEvent event = new AggregationEvent();
            if (this.source != null) {
                event.eventQueue.addAll(this.source);
            }
            event.eventSourceName = Type.AGGREGATION_ROOT.getDefaultSourceName();
            return event;
        }

    }
}
